﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using SimpleData.Infrastructure.Utils;

namespace SimpleData.ObjectModel.Internals
{

	/// <summary>
	/// 
	/// </summary>
	public sealed class DocumentValidatorExpressionBuilder : ExpressionBuilder
	{
		public List<FieldName> declaredFields = new List<FieldName>();

		public DocumentValidatorExpressionBuilder()
			: this( null, null )
		{ }

		/// <summary>
		/// 
		/// </summary>
		/// <param name="input"></param>
		/// <param name="context"></param>
		public DocumentValidatorExpressionBuilder( ParameterExpression input, ParameterExpression context )
		{
			if ( input != null )
				this.Variables[ "input" ] = input;

			if ( context != null )
				this.Variables[ "context" ] = context;

			this.Input = input;
			this.Context = context;
		}

		public ParameterExpression DeclareInput()
		{
			this.Input = base.DeclareVar<object>( "input" );
			return this.Input;
		}

		public ParameterExpression DeclareContext()
		{
			this.Context = base.DeclareVar<DocumentValidatorContext>( "context" );
			return this.Context;
		}

		public ParameterExpression Input
		{ get; private set; }

		public ParameterExpression Context
		{ get; private set; }


		public void AssignFieldToInput( FieldName name )
		{
			base.Include( Expression.Assign( this.Input, this.GetFieldVar( name ) ) );
		}

		public ParameterExpression DeclareFieldVar( FieldName name, Type fieldType )
		{
			ParameterExpression variable = this.DeclareVar( this.GetVarName( name ), fieldType );
			base.Assign<DocumentValidatorContext>( variable, context => context.Document.Values[ name.FullName ] );
			return variable;
		}

		public ParameterExpression GetFieldVar( FieldName name )
		{
			ParameterExpression value;

			if ( this.Variables.TryGetValue( this.GetVarName( name ), out value ) )
				return value;
			else
				return null;
		}

		private string GetVarName( FieldName name )
		{
			int index = this.declaredFields.IndexOf( name );

			if ( index < 0 )
			{
				index = this.declaredFields.Count;
				this.declaredFields.Add( name );
			}
			return String.Concat( "f", index );
		}
	}
}
